﻿using ICSharpCode.AvalonEdit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Xml;
using Xpom_Xpum__Integrated_Development_Environment.Data.Configuration;

namespace Xpom_Xpum__Integrated_Development_Environment.View.Controls
{
    public class TextEditorView : TextEditor
    {
        #region Constructors

        static TextEditorView()
        {
            FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(
                default(string), OnItemsPropertyChanged);

            Text2Property = DependencyProperty.Register("Text2",
               typeof(string), typeof(TextEditorView), metadata);
        }

        public TextEditorView()
        {
            Stream xshd_stream = File.OpenRead(GlobalSettings.SDKPath + "Syntax Highlighting/JavaScript.xshd");
            XmlTextReader xshd_reader = new XmlTextReader(xshd_stream);
            this.SyntaxHighlighting = ICSharpCode.AvalonEdit.Highlighting.Xshd.HighlightingLoader.Load(xshd_reader, ICSharpCode.AvalonEdit.Highlighting.HighlightingManager.Instance);
            xshd_reader.Close();
            xshd_stream.Close();

            FontFamily = new System.Windows.Media.FontFamily("Consolas");
            FontSize = 12.5;

            ContextMenu = new ContextMenu();
            // Undo
            UndoMenuItem = new MenuItem();
            UndoMenuItem.Header = "Undo";
            UndoMenuItem.Click += (sender, e) =>
            {
                this.Undo();
            };
            ContextMenu.Items.Add(UndoMenuItem);
            // Redo
            RedoMenuItem = new MenuItem();
            RedoMenuItem.Header = "Redo";
            RedoMenuItem.Click += (sender, e) =>
            {
                this.Redo();
            };
            ContextMenu.Items.Add(RedoMenuItem);
            // Separator
            ContextMenu.Items.Add(new Separator());
            // Cut
            CutMenuItem = new MenuItem();
            CutMenuItem.Header = "Cut";
            CutMenuItem.Click += (sender, e) =>
            {
                this.Cut();
            };
            ContextMenu.Items.Add(CutMenuItem);
            // Copy
            CopyMenuItem = new MenuItem();
            CopyMenuItem.Header = "Copy";
            CopyMenuItem.Click += (sender, e) =>
            {
                this.Copy();
            };
            ContextMenu.Items.Add(CopyMenuItem);
            // Paste
            PasteMenuItem = new MenuItem();
            PasteMenuItem.Header = "Paste";
            PasteMenuItem.Click += (sender, e) =>
            {
                this.Paste();
            };
            ContextMenu.Items.Add(PasteMenuItem);
            // Separator
            ContextMenu.Items.Add(new Separator());
            // Select All
            SelectAllMenuItem = new MenuItem();
            SelectAllMenuItem.Header = "Select All";
            SelectAllMenuItem.Click += (sender, e) =>
            {
                this.SelectAll();
            };
            ContextMenu.Items.Add(SelectAllMenuItem);
        }

        #endregion

        #region Commands

        #endregion

        #region Fields

        public static readonly DependencyProperty Text2Property;

        private MenuItem UndoMenuItem;
        private MenuItem RedoMenuItem;
        private MenuItem CutMenuItem;
        private MenuItem CopyMenuItem;
        private MenuItem PasteMenuItem;
        private MenuItem SelectAllMenuItem;

        #endregion

        #region Properties

        public string Text2
        {
            get
            {
                return GetValue(Text2Property).ToString();
            }
            set
            {
                SetValue(Text2Property, value);
            }
        }

        #endregion

        #region Methods

        protected override void OnTextChanged(EventArgs e)
        {
            base.OnTextChanged(e);
            try
            {
                if (Text2 != Text)
                    Text2 = Text;
            }
            catch { }
        }

        protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);
        }

        protected override void OnMouseDoubleClick(System.Windows.Input.MouseButtonEventArgs e)
        {
            base.OnMouseDoubleClick(e);
        }

        protected override void OnTextInput(System.Windows.Input.TextCompositionEventArgs e)
        {
            base.OnTextInput(e);
        }

        private static void OnItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            try
            {
                if ((d as TextEditor).Text != e.NewValue.ToString())
                    (d as TextEditor).Text = e.NewValue.ToString();
            }
            catch { }
        }

        public bool Find(string findWhat, bool findPrevious = false,
            bool matchCase = false, bool matchWholeWord = false, bool useWildcards = false)
        {
            Regex regex = GetRegEx(findWhat, findPrevious, matchCase, matchWholeWord, useWildcards);
            int start = regex.Options.HasFlag(RegexOptions.RightToLeft) ?
            this.SelectionStart : this.SelectionStart + this.SelectionLength;
            Match match = regex.Match(this.Text, start);

            if (!match.Success)  // start again from beginning or end
            {
                if (regex.Options.HasFlag(RegexOptions.RightToLeft))
                    match = regex.Match(this.Text, this.Text.Length);
                else
                    match = regex.Match(this.Text, 0);
            }

            if (match.Success)
            {
                this.Select(match.Index, match.Length);
                ICSharpCode.AvalonEdit.Document.TextLocation loc = this.Document.GetLocation(match.Index);
                this.ScrollTo(loc.Line, loc.Column);
            }

            return match.Success;
        }

        private Regex GetRegEx(string findWhat, bool findPrevious = false,
            bool matchCase = false, bool matchWholeWord = false, bool useWildcards = false)
        {
            RegexOptions options = RegexOptions.None;

            if (!matchCase)
                options |= RegexOptions.IgnoreCase;

            if (findPrevious)
                options |= RegexOptions.RightToLeft;

            if (useWildcards)
                findWhat = findWhat.Replace("\\*", ".*").Replace("\\?", ".");

            if (matchWholeWord)
                findWhat = "\\b" + findWhat + "\\b";

            return new Regex(findWhat, options);
        }

        public void ForceFocus()
        {
            Keyboard.Focus(this);
            this.Focus();
        }

        #endregion
    }
}
